#include "crossbit/ELFMemoryImage.h"
#include "crossbit/VInst.h"

#include "arch/mips/MIPSInterpreter.h"
#include "arch/mips/MIPSVBasicBlockBuilder.h"

#include "MIPSInst.h"

using namespace crossbit;

namespace crossbit
{
#define INSTLEN		4

#define DELAYREG1	34
#define DELAYREG2	35
#define TEMPREG1	36
#define TEMPREG2	37
#define TEMPREG3	38 
#define TEMPREG4	39
#define TEMPREG5	40

    MIPSOpsFmt* pInst;
    MIPSProcessorState *pState;
    XTMemAddr PC;

    void deSpecial(void* arg);
    void deRegimm(void* arg);
    void deJ(void* arg);
    void deJAL(void* arg);
    void deBEQ(void* arg);
    void deBNE(void* arg);
    void deBLEZ(void* arg);
    void deBGTZ(void* arg);
    void deADDI(void* arg);
    void deADDIU(void* arg);
    void deSLTI(void* arg);
    void deSLTIU(void* arg);
    void deANDI(void* arg);
    void deORI(void* arg);
    void deXORI(void* arg);
    void deLUI(void* arg);
    void deCOP0(void* arg);
    void deCOP1(void* arg);
    void deCOP2(void* arg);
    void deCOP1X(void* arg);
    void deBEQL(void* arg);
    void deBNEL(void* arg);
    void deBLEZL(void* arg);
    void deBGTZL(void* arg);
    void deSpecial2(void* arg);
    void deJALX(void* arg);
    void deSpecial3(void* arg);
    void deLB(void* arg);
    void deLH(void* arg);
    void deLWL(void* arg);
    void deLW(void* arg);
    void deLBU(void* arg);
    void deLHU(void* arg);
    void deLWR(void* arg);
    void deSB(void* arg);
    void deSH(void* arg);
    void deSWL(void* arg); 
    void deSW(void* arg);
    void deSWR(void* arg);
    void deLL(void* arg);
    void deLWC1(void* arg);
    void deLWC2(void* arg);
    void dePREF(void* arg);
    void deLDC1(void* arg);
    void deLDC2(void* arg);
    void deSC(void* arg);
    void deSWC1(void* arg);
    void deSWC2(void* arg);
    void deSDC1(void* arg);
    void deSDC2(void* arg);
    void deUndef(void* arg);

    void deSLL(void* arg);
    void deMOVCI(void* arg);
    void deSRL(void* arg);
    void deSRA(void* arg);
    void deSLLV(void* arg);
    void deSRLV(void* arg);
    void deSRAV(void* arg);
    void deJR(void* arg);	//JR, JR.HB
    void deJALR(void* arg);	//JALR, JALR.HB
    void deMOVZ(void* arg);
    void deMOVN(void* arg);
    void deSYSCALL(void* arg);
    void deBREAK(void* arg);
    void deSYNC(void* arg);
    void deMFHI(void* arg);
    void deMTHI(void* arg);
    void deMFLO(void* arg);
    void deMTLO(void* arg);
    void deMULT(void* arg);
    void deMULTU(void* arg);
    void deDIV(void* arg);
    void deDIVU(void* arg);
    void deADD(void* arg);
    void deADDU(void* arg);
    void deSUB(void* arg);
    void deSUBU(void* arg);
    void deAND(void* arg);
    void deOR(void* arg);
    void deXOR(void* arg);
    void deNOR(void* arg);
    void deSLT(void* arg);
    void deSLTU(void* arg);
    void deTGE(void* arg);
    void deTGEU(void* arg);
    void deTLT(void* arg);
    void deTLTU(void* arg);
    void deTEQ(void* arg);
    void deTNE(void* arg);

    void deBLTZ(void* arg);
    void deBGEZ(void* arg);
    void deBLTZL(void* arg);
    void deBGEZL(void* arg);
    void deTGEI(void* arg);
    void deTGEIU(void* arg);
    void deTLTI(void* arg);
    void deTLTIU(void* arg);
    void deTEQI(void* arg);
    void deTNEI(void* arg);
    void deBLTZAL(void* arg);
    void deBGEZAL(void* arg);
    void deBLTZALL(void* arg);
    void deBGEZALL(void* arg);
    void deSYNCI(void* arg);

    //COP1
    void deCOP1S(void* arg);
    void deMFC1(void* arg);
    void deCFC1(void* arg);
    void deMTC1(void* arg);
    void deCTC1(void* arg);
    void deBC1(void* arg);
    void deCOP1D(void* arg);
    void deCOP1W(void* arg);

    void deADD_S(void* arg);
    void deADD_D(void* arg);
    void deSUB_S(void* arg);
    void deSUB_D(void* arg);
    void deDIV_S(void* arg);
    void deDIV_D(void* arg);
    void deMUL_S(void* arg);
    void deMUL_D(void* arg);
    void deABS_S(void* arg);
    void deABS_D(void* arg);
    void deMOV_S(void* arg);
    void deMOV_D(void* arg);
    void deNEG_S(void* arg);
    void deNEG_D(void* arg);
    void deCVT_W_D(void* arg);
    void deC_EQ_S(void* arg);
    void deC_EQ_D(void* arg);
    void deC_ULE_S(void* arg);
    void deC_LT_S(void* arg);
    void deC_LT_D(void* arg);
    void deC_LE_S(void* arg);
    void deC_LE_D(void* arg);

    void deCVT_D_S(void* arg);
    void deCVT_W_S(void* arg);
    void deCVT_S_W(void* arg);
    void deCVT_D_W(void* arg);

    void deCVT_S_D(void* arg);

    typedef void (*Defunc)(void*);

    typedef struct
    {
        XTCPStr name;
        Defunc f;
    } FuncTable;

    FuncTable deTable[] = 
    { 											//op:
        {"SPECIAL", deSpecial}, {"REGIMM", deRegimm}, {"J", deJ}, {"JAL", deJAL},	//0 - 4
        {"BEQ", deBEQ}, {"BNE", deBNE}, {"BLEZ", deBLEZ}, {"BGTZ", deBGTZ},
        {"ADDI", deADDI}, {"ADDIU", deADDIU}, {"SLTI", deSLTI}, {"SLTIU", deSLTIU},
        {"ANDI", deANDI}, {"ORI", deORI}, {"XORI", deXORI}, {"LUI", deLUI},
        {"Undef", deUndef},{"COP1", deCOP1},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},	
        {"LB", deLB},{"LH", deLH},{"LWL", deLWL},{"LW", deLW},
        {"LBU", deLBU},{"LHU", deLHU},{"LWR", deLWR},{"Undef", deUndef},
        {"SB", deSB},{"SH", deSH},{"SWL", deSWL},{"SW", deSW},
        {"Undef", deUndef},{"Undef", deUndef},{"SWR", deSWR},{"Undef", deUndef},
        {"LL", deLL},{"LWC1", deLWC1},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"SC", deSC},{"SWC1", deSWC1},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef}
    };

    FuncTable deSpecialTable[] = 
    {
        {"SLL", deSLL},{"Undef", deUndef},{"SRL", deSRL},{"SRA", deSRA},
        {"SLLV", deSLLV},{"Undef", deUndef},{"SRLV", deSRLV},{"SRAV", deSRAV},
        {"JR", deJR},{"JALR", deJALR},{"Undef", deUndef},{"Undef", deUndef},
        {"SYSCALL", deSYSCALL},{"BREAK", deBREAK},{"Undef", deUndef},{"Undef", deUndef},
        {"MFHI", deMFHI},{"Undef", deUndef},{"MFLO", deMFLO},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"MULT", deMULT},{"MULTU", deMULTU},{"DIV", deDIV},{"DIVU", deDIVU},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"ADDU", deADDU},{"Undef", deUndef},{"SUBU", deSUBU},
        {"AND", deAND},{"OR", deOR},{"XOR", deXOR},{"NOR", deNOR},
        {"Undef", deUndef},{"Undef", deUndef},{"SLT", deSLT},{"SLTU", deSLTU},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef}
    };

    FuncTable deRegimmTable[]  = 
    {
        {"BLTZ", deBLTZ},{"BGEZ", deBGEZ},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"BLTZAL", deBLTZAL},{"BGEZAL", deBGEZAL},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef}
    };

    FuncTable deCOP1Table[] = 
    {
        {"MFC1", deMFC1},{"Undef", deUndef},{"CFC1", deCFC1},{"Undef", deUndef},
        {"MTC1", deMTC1},{"Undef", deUndef},{"CTC1", deCTC1},{"Undef", deUndef},
        {"BC1", deBC1},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"cop1s", deCOP1S},{"cop1d", deCOP1D},{"Undef", deUndef},{"Undef", deUndef},
        {"cop1w", deCOP1W},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef}
    };

    FuncTable deCOP1STable[]  =
    {
        {"ADD.S", deADD_S},{"SUB.S", deSUB_S},{"MUL_S", deMUL_S},{"DIV.S", deDIV_S},
        {"Undef", deUndef},{"ABS.S", deABS_S},{"MOV.S", deMOV_S},{"NEG.S", deNEG_S},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"CVT.D.S", deCVT_D_S},{"Undef", deUndef},{"Undef", deUndef},
        {"CVT.W.S", deCVT_W_S},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"C.EQ.S", deC_EQ_S},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"C.ULE.S", deC_ULE_S},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"C.LT.S", deC_LT_S},{"Undef", deUndef},{"C.LE.S", deC_LE_S},{"Undef", deUndef}
    };

    FuncTable deCOP1DTable[]  =
    {
        {"ADD.D", deADD_D},{"SUB.D", deSUB_D},{"MUL_D", deMUL_D},{"DIV_D", deDIV_D},
        {"Undef", deUndef},{"ABS.D", deABS_D},{"MOV.D", deMOV_D},{"NEG.D", deNEG_D},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"CVT.S.D", deCVT_S_D},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"CVT.W", deCVT_W_D},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"C.EQ", deC_EQ_D},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"C.LT", deC_LT_D},{"Undef", deUndef},{"C.LE", deC_LE_D},{"Undef", deUndef}
    };

    FuncTable deCOP1WTable[]  =
    {
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"CVT.S.W", deCVT_S_W},{"CVT.D", deCVT_D_W},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
        {"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef}
    };


    void deSpecial(void* arg)
    {
        deSpecialTable[pInst->func].f(arg);
    }

    void deRegimm(void* arg)
    {
        deRegimmTable[pInst->bl].f(arg);
    }

    void deCOP1(void* arg)
    {
        deCOP1Table[pInst->rs].f(arg);
    }

    void deCOP1S(void* arg)
    {
        deCOP1STable[pInst->func].f(arg);
    }

    void deCOP1D(void* arg)
    {
        deCOP1DTable[pInst->func].f(arg);
    }

    void deCOP1W(void* arg)
    {
        deCOP1WTable[pInst->func].f(arg);
    }

    void deJ(void* arg)
    {/*
        unsigned int w = *((unsigned int*)arg);
        unsigned target = ((w&0x03ffffff) << 2) |((PC+INSTLEN)&0xf0000000);
      */
        printf("0x%08x\n", PC);
        exit(1);
    }

    void deJAL(void* arg)
    {
        printf("0x%08x\n", PC);
        exit(1);
    }

    void deBEQ(void* arg)
    {
        unsigned address = PC + 4 + ((signed short)pInst->offset <<2 );
        bool is_jump = false;
        if( pInst -> rs == pInst -> rt ) {
            is_jump = true;
        } else {
            ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
            ((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rs, DELAYREG1) );
            ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
            ((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rt, DELAYREG2) );
        }

        pInst = (MIPSOpsFmt*)(PC+4);
        deTable[pInst->op].f(arg);

        if ( is_jump ) {
            if( PC == address ) {
                ((MIPSVBasicBlockBuilder*)arg)->add( JMP(0, address) );
                PC += 4;
            } else {
                PC = address;
                pInst = (MIPSOpsFmt*)(PC);
                deTable[pInst->op].f(arg);
            }
        } else {
            ((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(EQ, DELAYREG1, DELAYREG2, 0, address) );
            PC = PC + 4;
        }

    }

    void deBNE(void* arg)
    {
        unsigned address = PC + 4 + ((signed short)pInst->offset <<2 );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rs, DELAYREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rt, DELAYREG2) );

        pInst = (MIPSOpsFmt*)(PC+4);

        deTable[pInst->op].f(arg);

        ((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(NE, DELAYREG1, DELAYREG2, 0, address) );

        PC = PC + 4;
    }

    void deBLEZ(void* arg)
    {
        unsigned address = PC + 4 + ((signed short)pInst->offset << 2 );

        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rs, DELAYREG1) );

        pInst = (MIPSOpsFmt*)(PC+4);
        deTable[pInst->op].f(arg);

        ((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(LE, DELAYREG1, 0, 0, address) );

        PC = PC + 4;
    }

    void deBGTZ(void* arg)
    {
        unsigned address = PC + 4 + ((signed short)pInst->offset << 2 );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rs, DELAYREG1) );

        pInst = (MIPSOpsFmt*)(PC+4);
        deTable[pInst->op].f(arg);

        ((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(GT, DELAYREG1, 0, 0, address) );
        PC = PC + 4;
    }

    void deADDI(void* arg)
    {
        printf("0x%08x\n", PC);
        exit(1);
    }

    void deADDIU(void* arg)
    {
        //			((MIPSVBasicBlockBuilder*)arg)->add( LI(((int)(signed short)pInst->offset), TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET( pInst->rrs, pInst->rrs) );
        //			((MIPSVBasicBlockBuilder*)arg)->add( ADD( TEMPREG1, pInst->rrs, pInst->bl) );
        ((MIPSVBasicBlockBuilder*)arg)->add( ADDI(((int)(signed short)pInst->offset), pInst -> rrs, pInst -> bl) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT( pInst->bl, pInst->bl) );
    }

    void deSLTI(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI((int)(signed short)pInst->offset, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( CMP(LT, pInst->rs, TEMPREG1, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT( pInst->rt, pInst->rt) );
    }

    void deSLTIU(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI((int)(signed short)pInst->offset, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( CMP(BE, pInst->rs, TEMPREG1, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT( pInst->rt, pInst->rt) );
    }

    void deANDI(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->offset, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG1, pInst->rs, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) );
    }

    void deORI(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->offset, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rrs, pInst->rrs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( OR(TEMPREG1, pInst->rrs, pInst->bl) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->bl, pInst->bl) );
    }

    void deXORI(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->offset, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( XOR(TEMPREG1, pInst->rs, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) );
    }

    void deLUI(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( LI((pInst->offset<<16), pInst->bl) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->bl, pInst->bl));
    }

    void deLB(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET( pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LD( pInst->rs, 
                                                 ((int)(signed short)pInst->offset), BYTE, pInst->rt) );        
        ((MIPSVBasicBlockBuilder*)arg)->add( SEXT(pInst->rt, BYTE, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) ); 
    }

    void deLH(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LD(pInst->rs,
                                                ((int)(signed short)pInst->offset), HALFWORD, pInst->rt));
        ((MIPSVBasicBlockBuilder*)arg)->add( SEXT(pInst->rt, HALFWORD, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) );
    }

    void deLWL(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->offset, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( ADD(pInst->rs, TEMPREG1, TEMPREG5) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(0xfffffffc, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG5, TEMPREG1, TEMPREG2) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LD(TEMPREG2, 0, WORD, TEMPREG2) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(0x3, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG5, TEMPREG1, TEMPREG5) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SLL(TEMPREG5, TEMPREG1, TEMPREG5) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(24, TEMPREG3) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SUB(TEMPREG3, TEMPREG5, TEMPREG3) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SLL(TEMPREG2, TEMPREG3, TEMPREG2) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(0xffffffff, TEMPREG4) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SLL(TEMPREG4, TEMPREG3, TEMPREG4) );
        ((MIPSVBasicBlockBuilder*)arg)->add( NOT(TEMPREG4, TEMPREG4) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND(pInst->rt, TEMPREG4, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( OR(pInst->rt, TEMPREG2, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) );
    }

    void deLWR(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->offset, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( ADD(pInst->rs, TEMPREG1, TEMPREG4) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(0xfffffffc, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG4, TEMPREG1, TEMPREG2) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LD(TEMPREG2, 0, WORD, TEMPREG2) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(0x3, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG4, TEMPREG1, TEMPREG4) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SLL(TEMPREG4, TEMPREG1, TEMPREG4) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SRL(TEMPREG2, TEMPREG4, TEMPREG2) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(0xffffffff, TEMPREG3) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SRL(TEMPREG3, TEMPREG4, TEMPREG3) );
        ((MIPSVBasicBlockBuilder*)arg)->add( NOT(TEMPREG3, TEMPREG3) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND(pInst->rt, TEMPREG3, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( OR(pInst->rt, TEMPREG2, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) );
    }

    void deLW(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET( pInst->rrs, pInst->rrs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LD( pInst->rrs, 
                                                 ((int)(signed short)pInst->offset), WORD, pInst->bl) );        
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->bl, pInst->bl) ); 
    }

    void deLBU(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LD(pInst->rs, 
                                                ((int)(signed short)pInst->offset), BYTE, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( ZEXT(pInst->rt, BYTE, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) );
    }

    void deLHU(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET( pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LD( pInst->rs, 
                                                 ((int)(signed short)pInst->offset), HALFWORD, pInst->rt) );        
        ((MIPSVBasicBlockBuilder*)arg)->add( ZEXT(pInst->rt, HALFWORD, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) ); 
    }

    void deSB(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( ST(pInst->rt, BYTE, pInst->rs, ((int)(signed short)pInst->offset)) );
    }

    void deSH(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( ST(pInst->rt, HALFWORD, 
                                                pInst->rs, ((int)(signed short)pInst->offset)) );
    }

    void deSWL(void* arg)	//added newly
    {
        //deUndef(arg);
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->offset, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( ADD(pInst->rs, TEMPREG1, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(0xfffffffc, TEMPREG2) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG1, TEMPREG2, TEMPREG3) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LD(TEMPREG3, 0, WORD, TEMPREG4) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(0x3, TEMPREG2) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG1, TEMPREG2, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SLL(TEMPREG1, TEMPREG2, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(24, TEMPREG2) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SUB(TEMPREG2, TEMPREG1, TEMPREG2) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SRL(pInst->rt, TEMPREG2, TEMPREG5) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(0xffffffff, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SRL(TEMPREG1, TEMPREG2, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( NOT(TEMPREG1, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG4, TEMPREG1, TEMPREG4) );
        ((MIPSVBasicBlockBuilder*)arg)->add( OR(TEMPREG4, TEMPREG5, TEMPREG4) );
        ((MIPSVBasicBlockBuilder*)arg)->add( ST(TEMPREG4, WORD, TEMPREG3, 0) );
    }

    void deSWR(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->offset, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( ADD(pInst->rs, TEMPREG1, TEMPREG4) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(0xfffffffc, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG4, TEMPREG1, TEMPREG2) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LD(TEMPREG2, 0, WORD, TEMPREG3) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(0x3, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG4, TEMPREG1, TEMPREG4) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SLL(TEMPREG4, TEMPREG1, TEMPREG4) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SLL(pInst->rt, TEMPREG4, TEMPREG5) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(0xffffffff, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SLL(TEMPREG1, TEMPREG4, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( NOT(TEMPREG1, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG3, TEMPREG1, TEMPREG3) );
        ((MIPSVBasicBlockBuilder*)arg)->add( OR(TEMPREG5, TEMPREG3, TEMPREG5) );
        ((MIPSVBasicBlockBuilder*)arg)->add( ST(TEMPREG5, WORD, TEMPREG2, 0) );
    }

    void deLL(void* arg)	//an atomic read, simply equal lw now
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET( pInst->rrs, pInst->rrs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LD( pInst->rrs, 
                                                 ((int)(signed short)pInst->offset), WORD, pInst->bl) );        
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->bl, pInst->bl) ); 
    }

    void deLWC1(void* arg)	//added newly
    {
        //deUndef(arg);
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( FLD(pInst->rs, 
                                                 ((int)(signed short)pInst->offset), WORD, pInst->rt) );
    }

    void deSC(void* arg)	//an atomic write, simply equal sw now
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rrs, pInst->rrs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->bl, pInst->bl) );
        ((MIPSVBasicBlockBuilder*)arg)->add( ST(pInst->bl, 
                                                WORD, pInst->rrs, ((int)(signed short)pInst->offset)) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(1, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( MOV(TEMPREG1, pInst->bl));
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->bl, pInst->bl) );
    }

    void deSWC1(void* arg)	//added newly
    {
        //deUndef(arg);
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( FST(pInst->rt, 
                                                 WORD, pInst->rs, ((int)(signed short)pInst->offset)) );

    }

    void deSW(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rrs, pInst->rrs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->bl, pInst->bl) );
        ((MIPSVBasicBlockBuilder*)arg)->add( ST(pInst->bl, 
                                                WORD, pInst->rrs, ((int)(signed short)pInst->offset)) );
    }

    void deSLL(void* arg)
    {
        if( pInst->ze == 0 && pInst->rt == 0 && pInst->rd == 0 )
        {
            //do nothing
        }
        else if( pInst->ze == 1 && pInst->rt == 0 && pInst->rd == 0 )
        {
            //do nothing
        }
        else
        {
            ((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->ze, TEMPREG1) );
            ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt));
            ((MIPSVBasicBlockBuilder*)arg)->add( SLL(pInst->rt, TEMPREG1, pInst->rd) );
            ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd));
        }
    }

    void deMOVCI(void* arg);

    void deSRL(void* arg)	//don't consider ROTR
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->ze, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SRL(pInst->rt, TEMPREG1, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
    }

    void deSRA(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->ze, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SRA(pInst->rt, TEMPREG1, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
    }

    void deSLLV(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(0x1f, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND(pInst->rs, TEMPREG1, TEMPREG2) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SLL(pInst->rt, TEMPREG2, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
    }

    void deSRLV(void* arg)
    {	
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(0x1f, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND(pInst->rs, TEMPREG1, TEMPREG2) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SRL(pInst->rt, TEMPREG2, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
    }

    void deSRAV(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(0x1f, TEMPREG1) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND( TEMPREG1, pInst->rs, TEMPREG2) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SRA(pInst->rt, TEMPREG2, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
    }

    void deJR(void* arg)	//JR, JR.HB
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rs, DELAYREG1) );
        bool isReturn = false;
        if( pInst -> rs == 31 ) {
            isReturn = true;
        }
        pInst = (MIPSOpsFmt*)(PC+4);
        deTable[pInst->op].f(arg);

		// FIXME: turn off return stack
		//isReturn = false;

        if( isReturn ) {
            ((MIPSVBasicBlockBuilder*)arg)->add( RETURN(DELAYREG1, 0) );
        } else {
            ((MIPSVBasicBlockBuilder*)arg)->add( JMP(DELAYREG1, 0) );
        }

        PC = PC + 4;
    }

    void deMOVZ(void* arg);
    void deMOVN(void* arg);
    void deSYSCALL(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( SYSCALL );
    }

    void deBREAK(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( HALT(PC) );
    }

    void deSYNC(void* arg);

    void deMFHI(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(32, 32) );
        ((MIPSVBasicBlockBuilder*)arg)->add( MOV(32, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
    }

    void deMTHI(void* arg);

    void deMFLO(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(33, 33) );
        ((MIPSVBasicBlockBuilder*)arg)->add( MOV(33, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
    }

    void deMTLO(void* arg);
    void deMULT(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( MUL(pInst->rs, pInst->rt, 32, 33) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(32, 32) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(33, 33) );
    }

    void deMULTU(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( MULU(pInst->rs, pInst->rt, 32, 33) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(32, 32) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(33, 33) );
    }

    void deDIV(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( DIV(pInst->rs, pInst->rt, 33, 32) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(33, 33) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(32, 32) );
    }

    void deDIVU(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( DIVU(pInst->rs, pInst->rt, 33, 32) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(33, 33) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(32, 32) );
    }

    void deADD(void* arg);
    void deSUB(void* arg);

    void deSUBU(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( SUB(pInst->rs, pInst->rt, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
    }

    void deOR(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( OR(pInst->rs, pInst->rt, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
    }

    void deXOR(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( XOR(pInst->rs, pInst->rt, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
    }

    void deNOR(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( OR(pInst->rs, pInst->rt, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( NOT(pInst->rd, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
    }

    void deSLT(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( CMP(LT, pInst->rs, pInst->rt, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
    }

    void deSLTU(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( CMP(BE, pInst->rs, pInst->rt, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
    }

    void deTGE(void* arg);
    void deTGEU(void* arg);
    void deTLT(void* arg);
    void deTLTU(void* arg);
    void deTEQ(void* arg);
    void deTNE(void* arg);


    void deJALR(void* arg) //JALR, JALR.HB
    {
		// FIXME: turn off return stack (replace IF statements)
        //   ((MIPSVBasicBlockBuilder*)arg)->add( LI((PC+8), pInst->rd) );
        if( pInst -> rd == 31 ) {
            // change on 2009-2-14 by stt , change the 'return' from indirect jump to direct jump the 
            // the translated code.
            ((MIPSVBasicBlockBuilder*)arg)->add( LIRETURN((PC+8), pInst->rd) );
        } else {
            ((MIPSVBasicBlockBuilder*)arg)->add( LI((PC+8), pInst->rd) );
        }
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT( pInst->rd, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET( pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( MOV( pInst->rs, DELAYREG1) );
        pInst = (MIPSOpsFmt*)(PC+4);
        deTable[pInst->op].f(arg);
        ((MIPSVBasicBlockBuilder*)arg)->add( JMP(DELAYREG1,0) );
        PC = PC + 4;
    }

    void deADDU(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( ADD(pInst->rs, pInst->rt, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
    }

    void deAND(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( AND(pInst->rs, pInst->rt, pInst->rd) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
    }

    void deBLTZ(void* arg)
    {
        unsigned address = (PC+4+(((signed short)pInst->offset) <<2) );

        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rs, DELAYREG1) );

        pInst = (MIPSOpsFmt*)(PC+4);
        deTable[pInst->op].f(arg);

        ((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(LT, DELAYREG1, 0, 0, address) );

        PC = PC + 4;
    }

    void deBGEZ(void* arg)
    {
        unsigned address = PC + 4 + (((signed short)pInst->offset) << 2);

        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rs, DELAYREG1) );

        pInst = (MIPSOpsFmt*)(PC+4);
        deTable[pInst->op].f(arg);

        ((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(GE, DELAYREG1, 0, 0, address) );

        PC = PC + 4;
    }

    void deBLTZL(void* arg);
    void deBGEZL(void* arg);
    void deTGEI(void* arg);
    void deTGEIU(void* arg);
    void deTLTI(void* arg);
    void deTLTIU(void* arg);
    void deTEQI(void* arg);
    void deTNEI(void* arg);

    void deBLTZAL(void* arg)
    {
        unsigned address = (PC + 4 + (((signed short)pInst->offset) <<2));
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(PC+8, 31) );		//$ra : 31
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(31, 31) );		//$ra : 31

        /**
         * As delay slot will be executed first, so we should store
         * the operand in a reg which will not be used in the delay slot
         */
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rrs, pInst->rrs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rrs, DELAYREG1) );

        pInst = (MIPSOpsFmt*)(PC+4);
        deTable[pInst->op].f(arg);

        ((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(LT, DELAYREG1, 0, 0, address) );

        PC = PC + 4;
    }

    void deBGEZAL(void* arg)
    {
        unsigned int address = PC + 4 + ((signed short)pInst->offset << 2);
        ((MIPSVBasicBlockBuilder*)arg)->add( LI(PC+8, 31) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(31, 31) );
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
        ((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rs, DELAYREG1) );

        pInst = (MIPSOpsFmt*)(PC+4);
        deTable[pInst->op].f(arg);

        ((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(GE, DELAYREG1, 0, 0, address) );

        PC = PC + 4;
    }

    void deBLTZALL(void* arg);
    void deBGEZALL(void* arg);
    void deSYNCI(void* arg);

    void deMFC1(void* arg)
    {
        //deUndef(arg);
        ((MIPSVBasicBlockBuilder*)arg)->add( FST(pInst->rd, WORD, 0, pState->get(pInst->rt)) );
        ((MIPSVBasicBlockBuilder*)arg)->add( LD(0, pState->get(pInst->rt), WORD, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) );
    }

    void deCFC1(void* arg)
    {
        //dummy
        //printf("use instruction CFC1\n");
        //exit(1);
        //((MIPSVBasicBlockBuilder*)arg)->add( FST(pInst->rd, WORD, 0, interp_state->get(pInst->rt)) );
    }

    void deMTC1(void* arg)	//added newly
    {
        //deUndef(arg);
        ((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
        ((MIPSVBasicBlockBuilder*)arg)->add( ST(pInst->rt, WORD, 0, pState->get(pInst->rt)) );
        ((MIPSVBasicBlockBuilder*)arg)->add( FLD(0, pState->get(pInst->rt), WORD, pInst->rd) );
    }

    void deCTC1(void* arg)
    {
        //dummy
        //printf("use instruction CTC1\n");
        //exit(1);
        //((MIPSVBasicBlockBuilder*)arg)->add( FLD(0, interp_state->get(pInst->rt), WORD, pInst->rd) );
    }

    void deBC1(void* arg)
    {
        //printf("PC 0x%08x, \n", PC);

        if(pInst->rt == 1)
        {
            //printf("BC1T\n");

            unsigned int address = PC + 4 + ((signed short)pInst->offset << 2);

            ((MIPSVBasicBlockBuilder*)arg)->add( LD(0, pState->fpGet(MIPSProcessorState::$fcc), WORD, DELAYREG1));

            pInst = (MIPSOpsFmt*)(PC+4);
            deTable[pInst->op].f(arg);

            ((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(NE, 0, DELAYREG1, 0, address) );
            PC = PC + 4;
        }
        else if(pInst->rt == 0)
        {
            //printf("BC1F\n");

            unsigned int address = PC + 4 + ((signed short)pInst->offset << 2);

            ((MIPSVBasicBlockBuilder*)arg)->add( LD(0, pState->fpGet(MIPSProcessorState::$fcc), WORD, DELAYREG1));

            pInst = (MIPSOpsFmt*)(PC+4);
            deTable[pInst->op].f(arg);

            ((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(EQ, 0, DELAYREG1, 0, address) );

            PC = PC + 4;
        }
    }

    void deADD_S(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rd));
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rt));
        ((MIPSVBasicBlockBuilder*)arg)->add( FADDS() );
        ((MIPSVBasicBlockBuilder*)arg)->add( FPUTS(pInst->ze));
    }

    void deADD_D(void* arg)
    {
        //deUndef(arg);
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rd));
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rt));
        ((MIPSVBasicBlockBuilder*)arg)->add( FADDD() );
        ((MIPSVBasicBlockBuilder*)arg)->add( FPUTD(pInst->ze));
    }

    void deSUB_S(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rd));
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rt));
        ((MIPSVBasicBlockBuilder*)arg)->add( FSUBS() );
        ((MIPSVBasicBlockBuilder*)arg)->add( FPUTS(pInst->ze));
    }

    void deSUB_D(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rd));
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rt));
        ((MIPSVBasicBlockBuilder*)arg)->add( FSUBD() );
        ((MIPSVBasicBlockBuilder*)arg)->add( FPUTD(pInst->ze));
    }

    void deMUL_S(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rd));
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rt));
        ((MIPSVBasicBlockBuilder*)arg)->add( FMULS() );
        ((MIPSVBasicBlockBuilder*)arg)->add( FPUTS(pInst->ze));
    }

    void deMUL_D(void* arg)
    {
        //deUndef(arg);
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rd));
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rt));
        ((MIPSVBasicBlockBuilder*)arg)->add( FMULD() );
        ((MIPSVBasicBlockBuilder*)arg)->add( FPUTD(pInst->ze));
    }

    void deDIV_S(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rd));
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rt));
        ((MIPSVBasicBlockBuilder*)arg)->add( FDIVS() );
        ((MIPSVBasicBlockBuilder*)arg)->add( FPUTS(pInst->ze));
    }

    void deDIV_D(void* arg)
    {
        //deUndef(arg);
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rd));
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rt));
        ((MIPSVBasicBlockBuilder*)arg)->add( FDIVD() );
        ((MIPSVBasicBlockBuilder*)arg)->add( FPUTD(pInst->ze));
    }

    void deABS_S(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rd));
        ((MIPSVBasicBlockBuilder*)arg)->add( FABSS());
        ((MIPSVBasicBlockBuilder*)arg)->add( FPUTS(pInst->ze));
    }

    void deABS_D(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rd));
        ((MIPSVBasicBlockBuilder*)arg)->add( FABSD());
        ((MIPSVBasicBlockBuilder*)arg)->add( FPUTD(pInst->ze));
    }

    void deMOV_S(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rd));
        ((MIPSVBasicBlockBuilder*)arg)->add( FPUTS(pInst->ze));
    }

    void deMOV_D(void* arg)
    {
        //deUndef(arg);
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rd));
        ((MIPSVBasicBlockBuilder*)arg)->add( FPUTD(pInst->ze));
    }

    void deNEG_S(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rd));
        ((MIPSVBasicBlockBuilder*)arg)->add( FNEGS());
        ((MIPSVBasicBlockBuilder*)arg)->add( FPUTS(pInst->ze));
    }

    void deNEG_D(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rd));
        ((MIPSVBasicBlockBuilder*)arg)->add( FNEGD());
        ((MIPSVBasicBlockBuilder*)arg)->add( FPUTD(pInst->ze));
        //printf("PC: 0x%08x: neg.d\n", PC);
    }

    void deCVT_W_D(void* arg)
    {
        //deUndef(arg);
        ((MIPSVBasicBlockBuilder*)arg)->add( FCONV(pInst->rd, DOUBLE, pInst->ze, WORD) );
    }

    void deC_EQ_S(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FCMPS(EQ, pInst->rd, pInst->rt, MIPSProcessorState::$fcc) );
    }

    void deC_EQ_D(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FCMPD(EQ, pInst->rd, pInst->rt, MIPSProcessorState::$fcc) );
        //printf("PC:0x%08x, c.eq.d\n", PC);
    }

    void deC_ULE_S(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FCMPS(NA, pInst->rd, pInst->rt, MIPSProcessorState::$fcc) );
    }

    void deC_LT_S(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FCMPS(BE, pInst->rd, pInst->rt, MIPSProcessorState::$fcc) );
    }

    void deC_LT_D(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FCMPD(BE, pInst->rd, pInst->rt, MIPSProcessorState::$fcc) );
        //printf("PC:0x%08x, c.lt.d\n", PC);
    }

    void deC_LE_S(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FCMPS(NA, pInst->rd, pInst->rt, MIPSProcessorState::$fcc) );
    }

    void deC_LE_D(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FCMPD(NA, pInst->rd, pInst->rt, MIPSProcessorState::$fcc) );
        //printf("PC:0x%08x, c.le.d\n", PC);
    }

    void deCVT_D_S(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FCONV(pInst->rd, FLOAT, pInst->ze, DOUBLE) );
    }

    void deCVT_W_S(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FCONV(pInst->rd, FLOAT, pInst->ze, WORD) );
    }

    void deCVT_S_W(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FCONV(pInst->rd, WORD, pInst->ze, FLOAT) );
    }

    void deCVT_D_W(void* arg)
    {
        //deUndef(arg);
        ((MIPSVBasicBlockBuilder*)arg)->add( FCONV(pInst->rd, WORD, pInst->ze, DOUBLE) );
    }

    void deCVT_S_D(void* arg)
    {
        ((MIPSVBasicBlockBuilder*)arg)->add( FCONV(pInst->rd, DOUBLE, pInst->ze, FLOAT) );
    }

    void deUndef(void* arg)
    {
        printf("0x%08x:\t", PC);
        printf("Undef instruction: 0x%08x\n", *(int*)arg);
        exit(1);
    } 
}

void MIPSInterpreter::delaySlot( XTMemAddr addr )
{
    //MIPSOpsFmt* inst = (MIPSOpsFmt*)(mm_->map(PC));
    MIPSOpsFmt* inst = (MIPSOpsFmt*)(PC);
    deTable[inst->op].f( inst );
}

XTInt32 MIPSInterpreter::initStack(XTMemAddr sp)
{
    interp_state->put( 29, sp ); 
    return 0;
}

XTMemAddr MIPSInterpreter::decode(XTMemAddr at, VBlockBuilder *bb)
{
    PC = at;
    //			pInst = (MIPSOpsFmt*)(mm_->map(PC));
    pInst = (MIPSOpsFmt*)(PC);
    pState = (MIPSProcessorState*)(interp_state);
    deTable[pInst->op].f( bb );

    return (PC+4); 
}
